昨天我們介紹了使用 requests 來取得網頁原始碼,可是有些透過 JavaScript 渲染的網頁或是防爬蟲做得很好的 ASP.Net 都會讓我們難以取得原始碼,這時候我們就可以用模擬瀏覽器來進行爬蟲,模擬瀏覽器就像是有一個人會一直依照你的指令操作瀏覽器的感覺,另一個情形是如果要做搶票或搶課這種連續性的動作,模擬瀏覽器可以真的模仿使用者在操作瀏覽器,而且自動連續點擊,方便且不易被伺服器端發現(?
Selenium 其實支援很多種程式語言,但今天我們是用 Python 來操作,他其實是個用來自動測試的套件,但可以被應用來爬蟲跟連點~
先建立今天要用的虛擬環境與安裝第三方套件 selenium
pipenv shell
pipenv install selenium
還必須要下載一個 browser driver 依照你安裝的瀏覽器要選擇不同 driver
Chrome: https://chromedriver.chromium.org/
Firefox: https://github.com/mozilla/geckodriver/releases
下載完後記住執行檔的路徑,等一下會需要用到
物件宣告
from selenium import webdriver
driverPath = r"C:\\chromedriver.exe" #填入剛剛記下的路徑
driver = webdriver.Chrome(driverPath) # Chrome
driver = webdriver.Firefox(driverPath) #Firefox
切換瀏覽器到目標網址
driver.get("http://www.google.com")
取得目前所在網頁的標題
print(driver.title)
以ID搜尋物件
from selenium.webdriver.common.by import By
element = driver.find_element(by=By.ID, value="TargetID")
以Name搜尋物件
from selenium.webdriver.common.by import By
obj = driver.find_element(By.NAME, "IamBanana")
以連結內容搜尋物件
from selenium.webdriver.common.by import By
obj = driver.find_element(By.LINK_TEXT, "https://rootttt.com.tw")
以CSS搜尋物件
from selenium.webdriver.common.by import By
obj = driver.find_element(By.CSS_SELECTOR, "#car span.blue.wow")
執行 JavaScript 指令碼
driver.execute_script("alert(1)")
執行 submit
driver.find_element_by_id("submit").click()
填入資料
driver.find_element_by_id("username").send_keys("USERNAME")
點擊按鈕
driver.find_element_by_id("buttom1").click()
切換視窗
driver.switch_to.window("windowName")
意外出現的彈出式視窗可能導致整個自動化腳本崩潰,我們可以用這種方式切換到視窗上進一步把他消掉
alert = driver.switch_to.alert
alert.text() #取得彈出式視窗內的文字
alert.dismiss() #關閉彈出式視窗
上一頁與下一頁
driver.back() #上一頁
driver.forward() #下一頁
重新整理
driver.fresh()
看了上面各種語法之後,就可以利用你想要的動作完成一套自動化腳本來控制瀏覽器,讓他日以繼夜的加班工作(? 現在我們來看看一個應用實例。這是舊版台鐵的訂票模擬腳本,現在已經不能用了,所以我才敢放出來XD 不過大概應用實例就是這樣給大家參考一下。
注意!不要用這個去寫搶票程式,那樣違法,驗證碼一定要自己手動輸入,否則可能會有麻煩!!!
from selenium import webdriver
from selenium.webdriver.support.ui import Select
import time
import datetime
"""
注意!僅需修改 User Config 內的資訊
其餘切勿做任何修改!
"""
#User Config
personid = "A123456789"
train_number = 105
count = 1
from_station_code = 100
to_station_code = 149
date = "2019/03/16"
#Script Config
Endpoint = "http://railway.hinet.net/Foreign/TW/etno1.html"
#----------Functions-------------#
def Date_gap(target_date_str):
d1 = datetime.datetime.strptime(target_date_str,'%Y/%m/%d')
d2 = datetime.datetime.now()
days = ( d1 - d2 ).days
days += 1
if(days > 14):
print("訂票只能訂兩星期以內的日期")
exit()
elif days < 0:
print("日期輸入錯誤")
exit()
else:
return days
#----------Script Start----------#
Date_gap(date)
browser = webdriver.Chrome()
browser.get(Endpoint)
bperson_id = browser.find_element_by_id("person_id")
btrain_number = browser.find_element_by_id("train_no")
bticket_count = Select( browser.find_element_by_id("order_qty_str"))
bfrom_station = Select( browser.find_element_by_id("from_station"))
bto_station = Select( browser.find_element_by_id("to_station"))
bdate = Select( browser.find_element_by_id("getin_date"))
bperson_id.send_keys(personid)
btrain_number.send_keys(str(train_number))
bticket_count.select_by_visible_text(str(count))
bfrom_station.select_by_value(str(from_station_code))
bto_station.select_by_value(str(to_station_code))
bdate.select_by_value(date+"-"+str(Date_gap(date)))
bsubmit = browser.find_element_by_class_name("btn-primary")
print(bsubmit)
bsubmit.submit()
brand_input = browser.find_element_by_id("randInput")
captcha = input("請手動輸入驗證碼->")
brand_input.send_keys(captcha)
brand_submit = browser.find_element_by_id("sbutton")
brand_submit.submit()
berror = browser.find_element_by_class_name("alert-danger")
berror_reason = browser.find_element_by_tag_name("strong")
print(berror_reason.text)
其實這就像一步一步流程寫下去,就像在寫劇本(? 很簡單,只是有時候會噴一些不明所以的錯誤,可能是因為瀏覽器載入速度比腳本慢,所以要是當的使用 time.sleep()
來等候瀏覽器完成,推薦各位一個好用的工具叫 Selenium IDE 他可以利用瀏覽器錄製的方式自動產生 Script,有時候真的挺方便的~
參考資料
https://www.seleniumhq.org/docs/03_webdriver.jsp